<template>
  <div class="container">
    <div class="game-begin" v-if="!isBegin">
      <el-input placeholder=" 请输入您的游戏昵称..."></el-input>
      <div class="radio">
        <el-radio v-model="radio" label="1000">普通</el-radio>
        <el-radio v-model="radio" label="500">困难</el-radio>
        <el-radio v-model="radio" label="250">极难</el-radio>
      </div>
      <el-button type="success" @click="beginGame" class="fa fa-caret-square-o-right fa-1x"> 点击开始游戏</el-button>
    </div>
    <div v-else-if="isDeath">
      <div class="isDeath">
        <h3>你已经死亡</h3>
        <h4>你的得分: {{score}}</h4>
        <el-button @click="reBeginGame"> 点击重新开始</el-button>
      </div>
    </div>
    <div v-else v-for="(row,rowIndex) in snakeMap" :key="rowIndex">
      <div :class="{isFirstRow:rowIndex === 0}">
        <div v-for="(col,colIndex) in row" :key="colIndex">
          <div class="snake-body" :class="{isFoot: col.nodeType === 'foot',isSnake:col.nodeType === 'snake' }">
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
  import NodeType from "../comm/js/nodeType";
  import commUtils from "../comm/js/commUtils";

  export default {
    data() {
      return {
        name: "Snake",
        isBegin: false,
        snakeMap: null,
        maxRows: 20,
        maxCols: 22,
        interval: null,
        haveFoot: false,
        radio: 0,
        snakeNode: [],
        direction: 'left',
        isDeath: false,
        score: 0,
      }
    },
    methods: {
      initGame() {
        this.initMap();
        //绑定键盘按键事件
        document.onkeydown = this.processKeyEvent();
      },
      reBeginGame() {
        this.clearMap();
      },
      beginGame() {
        this.initGame();
        this.isBegin = true;
        this.isDeath = false;
        let _this = this;
        this.interval = setInterval(() => {
          if (!_this.isDeath) {
            _this.setFoot();
            _this.renderSnake();
          } else {
            window.clearInterval(_this.interval);
            _this.snakeMap = null;
            _this.snakeNode = [];
          }
        }, this.radio === 0 ? 500 : this.radio);
      },
      clearMap() {
        this.snakeNode = [];
        this.direction = 'left';
        this.isDeath = false;
        this.isBegin = false;
        this.snakeMap = null;
        this.score = 0;
        this.haveFoot = false;
      },
      processKeyEvent() {
        let _this = this;
        return (evt) => {
          evt = (evt) ? evt : window.event;
          if (evt.keyCode) {
            if (evt.keyCode === 27) {
              //do something
              _this.isBegin = false;
              clearInterval(_this.interval);
              _this.clearMap();
            } else if (evt.keyCode === 37) {
              //left
              if(_this.direction !== 'right' && _this.snakeNode.length >= 2){
                _this.direction = 'left';
              }else {
                _this.direction = 'left';
              }
            } else if (evt.keyCode === 38) {
              //up
              if(_this.direction !== 'down' && _this.snakeNode.length >= 2){
                _this.direction = 'up';
              }else{
                _this.direction = 'up';
              }
            } else if (evt.keyCode === 39) {
              //right
              if(_this.direction !== 'left' && _this.snakeNode.length >= 2){
                _this.direction = 'right';
              }else{
                _this.direction = 'right';
              }
            } else if (evt.keyCode === 40) {
              //down
              if(_this.direction !== 'up' && _this.snakeNode.length >= 2){
                _this.direction = 'down';
              }else{
                _this.direction = 'down';
              }
            }
          }
        }
      },
      /**
       * 初始化地图数据
       */
      initMap() {
        if (!this.snakeMap) {
          this.snakeMap = new Array(this.maxRows);
          for (let row = 0; row < this.maxRows; row++) {
            let cols = new Array(this.maxCols);
            for (let col = 0; col < this.maxCols; col++) {
              cols[col] = {row, col, nodeType: null};
            }
            this.$set(this.snakeMap, row, cols);
          }
        }
      },
      /**
       * 设置食物
       */
      setFoot() {
        if (!this.haveFoot) {
          let setFoot = false;
          while (!setFoot) {
            let row = Math.floor(Math.random() * 19);
            let col = Math.floor(Math.random() * 21);
            let tempArray;
            tempArray = this.snakeMap[row];
            if (tempArray[col].nodeType !== NodeType.TYPE_SNAKE) {
              tempArray[col].nodeType = NodeType.TYPE_FOOT;
              this.$set(this.snakeMap, row, tempArray);
              setFoot = true;
            }
          }
          this.haveFoot = true;
        }
      },
      /**
       * 渲染蛇身体
       */
      renderSnake() {
        if (this.snakeNode.length === 0) {
          //如果是第一次进入,生成一个蛇头
          let row = Math.floor(Math.random() * 15 + 5);
          let col = Math.floor(Math.random() * 25 + 5);
          let tempArray = this.snakeMap[row];
          if (tempArray[col].nodeType !== NodeType.TYPE_FOOT) {
            tempArray[col].nodeType = NodeType.TYPE_SNAKE;
            this.$set(this.snakeMap, row, tempArray);
            this.snakeNode.push({row, col})
          }
        } else {
          //渲染蛇的身体,模拟移动思路:删除蛇身体最后一个
          this.nextNode();
        }

      },
      /**死亡
       * 根据按键的方向计算,下一个移动的节点
       */
      nextNode() {
        let headerNode = this.snakeNode[0];
        let row = headerNode.row;
        let col = headerNode.col;
        switch (this.direction) {
          case 'left':
            if ((headerNode.col - 1) < 0) {
              this.isDeath = true;
            } else {
              col = headerNode.col - 1;
            }
            break;
          case 'up':
            if (headerNode.row - 1 < 0) {
              this.isDeath = true;
            } else {
              row = headerNode.row - 1;
            }
            break;
          case 'right':
            if (headerNode.col + 1 >= this.maxCols) {
              this.isDeath = true;
            } else {
              col = headerNode.col + 1;
            }
            break;
          case 'down':
            if (headerNode.row + 1 >= this.maxRows) {
              this.isDeath = true;
            } else {
              row = headerNode.row + 1;
            }
            break;
        }
        //判断下一个阶段是否为食物{}
        let nextNode = this.snakeMap[row][col];
        if (nextNode.nodeType === 'foot') {
          //如果下一个节点是食物
          this.haveFoot = false;
          this.snakeMap[row][col].nodeType = 'snake';
          this.snakeNode.unshift({row, col});
          this.score += 10;

        } else if (!nextNode.nodeType) {
          //下一个节点为正常的地图,下一个节点插入队列头,删除最后一个实现身体移动
          this.snakeMap[row][col].nodeType = 'snake';
          this.snakeNode.unshift({row, col});
          let tailNode = this.snakeNode.pop();
          this.snakeMap[tailNode.row][tailNode.col].nodeType = null;
        }else if ( nextNode.nodeType === 'snake'){
          this.isDeath = true;
        }
      }
    }
  }
</script>

<style scoped>
  .container {
    background-color: white;
    width: 550px;
    height: 500px;
    margin: 20px auto;
    box-shadow: 4px 4px 4px 4px #d6d6d6;
  }

  .game-begin {
    padding-top: 50px;
  }

  .isDeath {
    height: 200px;
    text-align: center;
    padding-top: 100px;
  }

  .isDeath h3 {
    color: red;
  }

  .el-input {
    width: 200px;
    margin: 20px auto;
    display: block;
  }

  .el-button {
    width: 200px;
  }

  .radio {
    margin: 20px;
  }

  .isFoot {
    background-color: #9d0000;
  }

  .isSnake {
    background-color: #99ff99;
    border-radius: 50%;
  }

  .snake-body {
    width: 25px;
    height: 25px;
    float: left;
    /*background-color: #99ff99;*/
  }
</style>
